/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package info.jerrinot.nettyloc; import com.hazelcast.logging.ILogger; import com.hazelcast.logging.Logger; import com.hazelcast.logging.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Utility that detects various properties specific to the current runtime * environment, such as Java version and the availability of the * {@code sun.misc.Unsafe} object. * <p> * You can disable the use of {@code sun.misc.Unsafe} if you specify * the system property <strong>io.netty.noUnsafe</strong>. */ public final class PlatformDependent { private static final ILogger logger = Logger.getLogger(PlatformDependent.class); private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile( "\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$"); private static final boolean HAS_UNSAFE = hasUnsafe0(); private static final long MAX_DIRECT_MEMORY = maxDirectMemory0(); private static final long ARRAY_BASE_OFFSET = arrayBaseOffset0(); static { if (!hasUnsafe()) { logger.info( "Your platform does not provide complete low-level API for accessing direct buffers reliably. " + "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " + "unstability."); } } /** * Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used for acclerated * direct memory access. */ public static boolean hasUnsafe() { return HAS_UNSAFE; } /** * Returns the maximum memory reserved for direct buffer allocation. */ public static long maxDirectMemory() { return MAX_DIRECT_MEMORY; } /** * Try to deallocate the specified direct {@link java.nio.ByteBuffer}. Please note this method does nothing if * the current platform does not support this operation or the specified buffer is not a direct buffer. */ public static void freeDirectBuffer(ByteBuffer buffer) { if (buffer.isDirect()) { if (hasUnsafe()) { PlatformDependent0.freeDirectBufferUnsafe(buffer); } else { PlatformDependent0.freeDirectBuffer(buffer); } } } public static long directBufferAddress(ByteBuffer buffer) { return PlatformDependent0.directBufferAddress(buffer); } public static int getInt(Object object, long fieldOffset) { return PlatformDependent0.getInt(object, fieldOffset); } public static long objectFieldOffset(Field field) { return PlatformDependent0.objectFieldOffset(field); } public static void copyMemory(long srcAddr, long dstAddr, long length) { PlatformDependent0.copyMemory(srcAddr, dstAddr, length); } public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) { PlatformDependent0.copyMemory(src, ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length); } public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) { PlatformDependent0.copyMemory(null, srcAddr, dst, ARRAY_BASE_OFFSET + dstIndex, length); } private static boolean hasUnsafe0() { boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false); if (logger.isFinestEnabled()) { logger.finest("-Dio.netty.noUnsafe: "+ noUnsafe); } if (noUnsafe) { logger.finest("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)"); return false; } // Legacy properties boolean tryUnsafe; if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) { tryUnsafe = SystemPropertyUtil.getBoolean("io.netty.tryUnsafe", true); } else { tryUnsafe = SystemPropertyUtil.getBoolean("org.jboss.netty.tryUnsafe", true); } if (!tryUnsafe) { logger.finest("sun.misc.Unsafe: unavailable (io.netty.tryUnsafe/org.jboss.netty.tryUnsafe)"); return false; } try { boolean hasUnsafe = PlatformDependent0.hasUnsafe(); if (logger.isFinestEnabled()) { logger.finest("sun.misc.Unsafe: "+ (hasUnsafe ? "available" : "unavailable")); } return hasUnsafe; } catch (Throwable t) { return false; } } private static long arrayBaseOffset0() { if (!hasUnsafe()) { return -1; } return PlatformDependent0.arrayBaseOffset(); } private static long maxDirectMemory0() { long maxDirectMemory = 0; try { // Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate. Class<?> vmClass = Class.forName("sun.misc.VM", true, ClassLoader.getSystemClassLoader()); Method m = vmClass.getDeclaredMethod("maxDirectMemory"); maxDirectMemory = ((Number) m.invoke(null)).longValue(); } catch (Throwable t) { // Ignore } if (maxDirectMemory > 0) { return maxDirectMemory; } try { // Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it. // Note that we are using reflection because Android doesn't have these classes. Class<?> mgmtFactoryClass = Class.forName( "java.lang.management.ManagementFactory", true, ClassLoader.getSystemClassLoader()); Class<?> runtimeClass = Class.forName( "java.lang.management.RuntimeMXBean", true, ClassLoader.getSystemClassLoader()); Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null); @SuppressWarnings("unchecked") List<String> vmArgs = (List<String>) runtimeClass.getDeclaredMethod("getInputArguments").invoke(runtime); for (int i = vmArgs.size() - 1; i >= 0; i --) { Matcher m = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN.matcher(vmArgs.get(i)); if (!m.matches()) { continue; } maxDirectMemory = Long.parseLong(m.group(1)); switch (m.group(2).charAt(0)) { case 'k': case 'K': maxDirectMemory *= 1024; break; case 'm': case 'M': maxDirectMemory *= 1024 * 1024; break; case 'g': case 'G': maxDirectMemory *= 1024 * 1024 * 1024; break; } break; } } catch (Throwable t) { // Ignore } if (maxDirectMemory <= 0) { maxDirectMemory = Runtime.getRuntime().maxMemory(); if (logger.isFinestEnabled()) { logger.finest("maxDirectMemory: +"+maxDirectMemory+" bytes (maybe)"); } } else { if (logger.isFinestEnabled()) { logger.finest("maxDirectMemory: "+maxDirectMemory+" bytes"); } } return maxDirectMemory; } private PlatformDependent() { // only static method supported } }